<script setup lang="ts">
import { computed, nextTick, onUnmounted, reactive } from 'vue';
import { createReusableTemplate } from '@vueuse/core';
import { useRouter } from 'vue-router';
import { getPaletteColorByNumber } from '@sa/color';
import { $t } from '@/locales';
import { useThemeStore } from '@/store/modules/theme';
import DardRetryChart from './card-retry-chart.vue';

const router = useRouter();
const themeStore = useThemeStore();

defineOptions({
  name: 'CardData'
});

interface Props {
  modelValue?: Api.Dashboard.CardCount;
}

const state = reactive({ width: 0 });
const gridCol = computed(() => {
  if (state.width >= 1600) {
    return 4;
  } else if (state.width >= 1024) {
    return 2;
  }
  return 1;
});

const getState = () => {
  state.width = document.documentElement.clientWidth;
};

nextTick(() => {
  getState();
  window.addEventListener('resize', getState);
});

onUnmounted(() => {
  // 移除监听事件
  window.removeEventListener('resize', getState);
});

const props = withDefaults(defineProps<Props>(), {
  modelValue: () => ({
    jobTask: {
      successNum: 0,
      failNum: 0,
      cancelNum: 0,
      stopNum: 0,
      totalNum: 0,
      successRate: 0
    },
    workFlowTask: {
      successNum: 0,
      failNum: 0,
      cancelNum: 0,
      stopNum: 0,
      totalNum: 0,
      successRate: 0
    },
    retryTask: {
      totalNum: 0,
      runningNum: 0,
      finishNum: 0,
      maxCountNum: 0,
      suspendNum: 0
    },
    retryTaskBarList: [],
    onLineService: {
      total: 0,
      clientTotal: 0,
      serverTotal: 0
    }
  })
});

interface CardData {
  key: string;
  title: string;
  tip: string;
  value: number;
  color: {
    start: string;
    end: string;
  };
  icon: string;
  bottom: { label: string; value: number }[];
}

// eslint-disable-next-line complexity
const cardData = computed<CardData[]>(() => [
  {
    key: 'jobTask',
    title: $t('page.home.jobTask'),
    tip: $t('page.home.jobTaskTip'),
    value: props.modelValue?.jobTask.totalNum ?? 0,
    color: {
      start: '#f5b386',
      end: '#FFD6BA'
    },
    icon: 'ant-design:profile-outlined',
    bottom: [
      {
        label: $t('common.success'),
        value: props.modelValue?.jobTask.successNum ?? 0
      },
      {
        label: $t('common.fail'),
        value: props.modelValue?.jobTask.failNum ?? 0
      },
      {
        label: $t('common.stop'),
        value: props.modelValue?.jobTask.stopNum ?? 0
      },
      {
        label: $t('common.cancel'),
        value: props.modelValue?.jobTask.cancelNum ?? 0
      }
    ]
  },
  {
    key: 'retryTask',
    title: $t('page.home.retryTask'),
    tip: $t('page.home.retryTaskTip'),
    value: props.modelValue?.retryTask.totalNum ?? 0,
    unit: '',
    color: {
      start: '#40e9c5',
      end: '#BEE3DB'
    },
    icon: 'ant-design:schedule-outlined',
    bottom: [
      {
        label: $t('common.success'),
        value: props.modelValue?.retryTask.finishNum ?? 0
      },
      {
        label: $t('common.running'),
        value: props.modelValue?.retryTask.runningNum ?? 0
      },
      {
        label: $t('page.manage.retryTask.status.maxRetryTimes'),
        value: props.modelValue?.retryTask.maxCountNum ?? 0
      },
      {
        label: $t('page.manage.retryTask.status.pauseRetry'),
        value: props.modelValue?.retryTask.suspendNum ?? 0
      }
    ]
  },
  {
    key: 'workflow',
    title: $t('page.home.workflow'),
    tip: $t('page.home.workflowTip'),
    value: props.modelValue?.workFlowTask.totalNum,
    unit: '',
    color: {
      start: '#ec6f6f',
      end: '#f99797'
    },
    icon: 'typcn:flow-merge',
    bottom: [
      {
        label: $t('common.success'),
        value: props.modelValue?.workFlowTask.successNum ?? 0
      },
      {
        label: $t('common.fail'),
        value: props.modelValue?.workFlowTask.failNum ?? 0
      },
      {
        label: $t('common.stop'),
        value: props.modelValue?.workFlowTask.stopNum ?? 0
      },
      {
        label: $t('common.cancel'),
        value: props.modelValue?.workFlowTask.cancelNum ?? 0
      }
    ]
  },
  {
    key: 'onlineServiceCount',
    title: $t('page.home.onlineServiceCount'),
    tip: $t('page.home.onlineServiceTip'),
    value: props.modelValue?.onLineService.total ?? 0,
    unit: '',
    color: {
      start: '#b686d4',
      end: '#c5a5d8'
    },
    icon: 'ant-design:database-outlined',
    bottom: [
      {
        label: $t('page.manage.machine.type.client'),
        value: props.modelValue?.onLineService.clientTotal ?? 0
      },
      {
        label: $t('page.manage.machine.type.server'),
        value: props.modelValue?.onLineService.serverTotal ?? 0
      }
    ]
  }
]);

interface GradientBgProps {
  gradientColor: string;
}

const [DefineGradientBg, GradientBg] = createReusableTemplate<GradientBgProps>();

function getGradientColor(color: CardData['color']) {
  const start = themeStore.darkMode ? getPaletteColorByNumber(color.start, 700) : color.start;
  const end = themeStore.darkMode ? getPaletteColorByNumber(color.end, 700) : color.end;
  return `linear-gradient(to bottom right, ${start}, ${end})`;
}
</script>

<template>
  <NCard :bordered="false" size="small" class="card-wrapper">
    <!-- define component start: GradientBg -->
    <DefineGradientBg v-slot="{ $slots, gradientColor }">
      <div class="rd-8px px-16px pb-4px pt-8px text-white" :style="{ backgroundImage: gradientColor }">
        <component :is="$slots.default" />
      </div>
    </DefineGradientBg>
    <!-- define component end: GradientBg -->

    <NGrid :cols="gridCol" responsive="screen" :x-gap="16" :y-gap="16">
      <NGi v-for="item in cardData" :key="item.key">
        <NSpin :show="false">
          <GradientBg
            :gradient-color="getGradientColor(item.color)"
            class="h-165px flex-1"
            :class="item.key === 'onlineServiceCount' ? 'cursor-pointer' : ''"
            @click="() => (item.key === 'onlineServiceCount' ? router.push('pods') : null)"
          >
            <div class="flex justify-between">
              <div class="align-center flex">
                <SvgIcon :icon="item.icon" class="text-26px" />
                <h3 class="ml-2 text-18px">{{ item.title }}</h3>
              </div>
              <NPopover trigger="hover">
                <template #trigger>
                  <NButton text>
                    <SvgIcon icon="ant-design:info-circle-outlined" class="text-20px color-white" />
                  </NButton>
                </template>
                {{ item.tip }}
              </NPopover>
            </div>
            <div class="flex">
              <CountTo :start-value="0" :end-value="item.value" class="text-30px text-white" />
            </div>
            <NProgress
              v-if="item.key === 'jobTask'"
              class="mb-24px h-20px pt-18px"
              type="line"
              color="#728bf9"
              rail-color="#ebebeb"
              :percentage="props.modelValue?.jobTask.successRate ?? 0"
              indicator-text-color="#fff"
            />
            <NProgress
              v-else-if="item.key === 'workflow'"
              class="mb-24px h-20px pt-18px"
              type="line"
              color="#728bf9"
              rail-color="#ebebeb"
              :percentage="props.modelValue?.workFlowTask.successRate ?? 0"
              indicator-text-color="#fff"
            />
            <DardRetryChart v-else-if="item.key === 'retryTask'" :model-value="props.modelValue?.retryTaskBarList" />
            <div v-else class="mb-12px h-32px"></div>
            <NDivider />
            <template v-for="(bottomItem, bottomIndex) in item.bottom" :key="bottomIndex">
              <NDivider v-if="bottomIndex !== 0" vertical />
              {{ bottomItem.label }}
              <CountTo :start-value="0" :end-value="bottomItem.value" class="text-white" />
            </template>
          </GradientBg>
        </NSpin>
      </NGi>
    </NGrid>
  </NCard>
</template>

<style scoped>
.n-divider {
  margin: 0px 0 6px;
}

.n-divider--vertical {
  margin: 0 1px 0 5px;
}

:deep(.n-progress-icon--as-text) {
  width: 60px !important;
}
</style>
